#pragma once
#include <iostream>
#include <functional>
#include <memory>

#define MAX_STATE 100

typedef std::function<void()> TimerHandle;
struct StateBase
{
	TimerHandle OnEnter;
	TimerHandle OnExec;
	TimerHandle OnExit;
	StateBase(){}
};
typedef std::shared_ptr<StateBase> StateBaseRef;

template<class K>
struct StateMachine
{
	StateMachine(K _maxState)
	{
		m_curState = K(0);
		m_maxState = _maxState;
		for (auto i = 0; i < _maxState; i++)
		{
			m_states[i] = StateBaseRef(new StateBase());
		}
	}

	void SetStateHandle(K state, TimerHandle OnEnter, TimerHandle OnExec, TimerHandle OnExit){
		m_states[state]->OnEnter = OnEnter;
		m_states[state]->OnExec = OnExec;
		m_states[state]->OnExit = OnExit;
	}

	K GetState()
	{
		return m_curState;
	}

	K GetPreState()
	{
		return m_preState;
	}

	void SetState(K state){
		if (state >= m_maxState)
		{
			return;
		}

		if ( m_curState != state)
		{
			auto pState = m_states[m_curState];
			if (pState && pState->OnExit)
			{
				pState->OnExit();
			}
		}

		m_preState = m_curState;
		m_curState = state;

		auto pState = m_states[state];
		if (pState && pState->OnEnter)
		{
			pState->OnEnter();
		}
	}

	void Update(){
		auto pState = m_states[m_curState];
		if ( pState && pState->OnExec){
			pState->OnExec();
		}
	}

	K m_preState;
	K m_curState;
	K m_maxState;
	StateBaseRef m_states[MAX_STATE];
};